﻿using SharpStockLib.DataAccess.CSVMappers;
using SharpStockLib.DataAccess.Providers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using SharpStockLib.Data;
using System.IO;
using System.Collections.Generic;

namespace SharpStockTests
{
    
    
    /// <summary>
    ///This is a test class for CSVProviderTest and is intended
    ///to contain all CSVProviderTest Unit Tests
    ///</summary>
    [TestClass()]
    public class CSVProviderTest
    {
        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for GetHistoricalDataAsync with no start or end date
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_FullData()
        {
            string csvDirectory = testContextInstance.DeploymentDirectory;
            const string instrumentName = "INTC";
            string csvPath = csvDirectory + "\\" + instrumentName + ".csv";

            CSVProvider target = new CSVProvider(csvPath, CSVType.YahooHisto);

            // Gets the number of lines in the CSV
            StreamReader reader = new StreamReader(csvPath);
            int nbLines = 0;
            while (!reader.EndOfStream)
            {
                reader.ReadLine();
                nbLines++;
            }
            reader.Dispose();

            IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, null, null);
            int nbLinesObs = 0;

            foreach(IData data in actual)
            {
                // Parsing tests : will check that the close is always positive
                Assert.IsTrue(data.Close > 0);
                nbLinesObs++;
            }

            // Overall test : will compare the number of lines read by the parser with the actual ones - 1 (because we skip the first one in the IObservable to avoid the header)
            Assert.AreEqual(nbLinesObs, nbLines - 1);
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync with start and end dates
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_WithBothDates()
        {
            string csvDirectory = testContextInstance.DeploymentDirectory;
            const string instrumentName = "INTC";
            string csvPath = csvDirectory + "\\" + instrumentName + ".csv";

            CSVProvider target = new CSVProvider(csvPath, CSVType.YahooHisto);

            DateTime startDate = new DateTime(2000, 6, 6);
            DateTime endDate = new DateTime(2001, 6, 9);
            int cpt = 0;

            IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, startDate, endDate);
            foreach(IData data in actual)
            {
                // Checks dates are fine
                Assert.IsTrue(data.Date <= endDate);
                Assert.IsTrue(data.Date >= startDate);
                cpt++;
            }

            // Final check : we actually have data !
            Assert.IsTrue(cpt > 0);
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync with start and end dates
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_WithStartDate()
        {
            string csvDirectory = testContextInstance.DeploymentDirectory;
            const string instrumentName = "INTC";
            string csvPath = csvDirectory + "\\" + instrumentName + ".csv";

            CSVProvider target = new CSVProvider(csvPath, CSVType.YahooHisto);

            DateTime startDate = new DateTime(2000, 6, 6);
            int cpt = 0;

            IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, startDate, null);
            foreach(IData data in actual)
            {
                // Checks dates are fine
                Assert.IsTrue(data.Date >= startDate);
                cpt++;
            }

            // Final check : we actually have data !
            Assert.IsTrue(cpt > 0);
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync with start and end dates
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_WithEndDate()
        {
            string csvDirectory = testContextInstance.DeploymentDirectory;
            const string instrumentName = "INTC";
            string csvPath = csvDirectory + "\\" + instrumentName + ".csv";

            CSVProvider target = new CSVProvider(csvPath, CSVType.YahooHisto);

            DateTime endDate = new DateTime(2001, 6, 9);
            int cpt = 0;

            IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, null, endDate);
            foreach(IData data in actual)
            {
                // Checks dates are fine
                Assert.IsTrue(data.Date <= endDate);
                cpt++;
            }

            // Final check : we actually have data !
            Assert.IsTrue(cpt > 0);
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync where the file given in input does not exist.
        ///An IOException should be thrown by the CSVProvider.
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_Fail_FileName()
        {
            string csvDirectory = testContextInstance.DeploymentDirectory;
            const string instrumentName = "DOES NOT EXIST";
            string csvPath = csvDirectory + "\\" + instrumentName + ".csv";

            CSVProvider target = new CSVProvider(csvPath, CSVType.YahooHisto);

            try
            {
                IObservable<IData> actual = target.GetHistoricalDataAsync(instrumentName, null, null);
                using (actual.Subscribe(data => Assert.Fail()))
                {
                }

                Assert.Fail();
            }
            catch (Exception e)
            {
                Assert.IsInstanceOfType(e, typeof(IOException));
            }
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync where the file given in input does not contain the expected data.
        ///An InvalidDataException should be thrown by the CSVProvider.
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_Fail_NotCSV()
        {
            string csvDirectory = testContextInstance.DeploymentDirectory;
            const string instrumentName = "NOT CSV";
            string csvPath = csvDirectory + "\\" + instrumentName + ".csv";

            CSVProvider target = new CSVProvider(csvPath, CSVType.YahooHisto);

            try
            {
                IObservable<IData> actual = target.GetHistoricalDataAsync(instrumentName, null, null);
                using (actual.Subscribe(data => Assert.Fail()))
                {
                }

                Assert.Fail();
            }
            catch (Exception e)
            {
                Assert.IsInstanceOfType(e, typeof(FileHelpers.FileHelpersException));
            }
        }

        /// <summary>
        ///A test for GetHistoricalData
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataTest_TradingBlox()
        {
            string csvDirectory = testContextInstance.DeploymentDirectory;
            const string instrumentName = "CL";
            string csvPath = csvDirectory + "\\CL20_I0B.TXT";

            CSVProvider target = new CSVProvider(csvPath, CSVType.TradingBloxHisto);

            // Gets the number of lines in the CSV
            StreamReader reader = new StreamReader(csvPath);
            int nbLines = 0;
            while (!reader.EndOfStream)
            {
                reader.ReadLine();
                nbLines++;
            }
            reader.Dispose();

            IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, null, null);
            int nbLinesObs = 0;

            foreach (IData data in actual)
            {
                // Parsing tests : will check that the close is always positive
                Assert.IsTrue(data.Close > 0);
                nbLinesObs++;
            }

            // Overall test : will compare the number of lines read by the parser with the actual ones
            Assert.AreEqual(nbLinesObs, nbLines);
        }
    }
}
